Skip to content

fix(web): escape fenced code language attributes - #10

Draft
lukisch wants to merge 2 commits into
mainfrom
fix/code-fence-language-escape-20261015
Draft

lukisch wants to merge 2 commits into
mainfrom
fix/code-fence-language-escape-20261015

Conversation

@lukisch

@lukisch lukisch commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

The web renderer inserts a fenced code block's language string directly into a quoted HTML class attribute. A quote followed by an img tag breaks out of that attribute and becomes additional markup in the preview. Escape this string with the existing HTML-escaping function before interpolation.

Add six Node built-in renderer tests that execute the shipped render functions without evaluating their HTML. Four malicious/attribute-special-character cases fail on exact base 0aea162 and pass after the fix. Ordinary language/body escaping and Unicode remain covered. Run these tests explicitly with Node22 in the existing eight native Windows/Linux CI cells.

Validation: 6 renderer cases and 9 existing web-companion tests pass locally; workflow YAML parses; git diff --check passes. Native CI and independent review remain pending. No version, dependencies of the application, release, service-worker cache or runtime mirror change.

Related to CodeQL alert3's preview HTML sink. This fixes the reproduced code-fence attribute injection only; it does not establish complete sanitizer safety or resolve every alert flow. Do not dismiss the alert on this evidence alone. No browser exploit was executed.

Author model: gpt-6.1-sol (Codex). Draft only; merges disabled. Independent model review pending.

Generated-with: gpt-6.1-sol (Codex)

lukisch commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

Zweitprüfung (Cloud-Bot), Head 10ab7ed: Code freigabereif, CI-Stand veraltet.

  • Fix: escapeHtml(codeBlockLang) im Fence-Renderer (web_companion/app.js) schließt den Attribut-Ausbruch über class="language-…". Der Körper wurde schon vorher escaped; es ist die einzige Stelle, an der codeBlockLang ungeprüft eingesetzt wurde.
  • Tests: tests/test_web_renderer.cjs führt den ausgelieferten Renderer in vm aus und wertet das HTML nicht aus. Die Assertion prüft die exakte Tag-Folge (<pre>, ein <code class=…>, </code>, </pre>). Damit fällt ein eingeschleustes <img> sicher auf. Die Fälle ">``&lt;img …&gt;'``, " onmouseover=", '<> &und">…` decken Quote-Breakout und Doppel-Escaping ab.
  • CI: Alle Windows-Zellen, Linux 3.12/3.13, Flutter und CodeQL sind grün. Rot sind nur Linux 3.10/3.11. Das ist die PySide6-6.12.0-Regression (none_dealloc in highlightBlock), nicht dieser Diff. Die Gegenmaßnahme !=6.12.0 liegt laut Kommentar in fix(deps): exclude Qt 6.12.0 highlighter refcount regression #11 bereits in main.
  • Offen: Der Head basiert auf 0aea162, main ist seitdem weitergelaufen. Bitte main einmergen und die CI neu laufen lassen. Der Node-Schritt ist dabei der eigentliche Nachweis, denn die Renderer-Tests laufen nur dort.
  • CodeQL-Alert 3: Wie in der Beschreibung steht, belegt das nur diesen Sink. Den Alert nicht allein darauf schließen.

Ein formales Approve ist nicht möglich, weil der PR vom selben Account stammt. Der Draft-/Merge-Hold bleibt unberührt.


Generated by Claude Code

lukisch commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

CI-Diagnose (Bot): Die roten Jobs (ubuntu 3.10/3.11) sind kein Defekt dieses PRs. test_self_test_preserves_existing_user_settings_bytes_and_mtime bricht mit Fatal Python error: none_dealloc in highlightBlock ab (PySide6 6.12.0, Qt-Highlighter-Refcount-Regression). Das behebt #11 (PySide6 6.12.0 ausgeschlossen). Empfehlung: #11 zuerst mergen, dann #10 auf master aktualisieren und CI neu laufen lassen. Der Code-Fence-Escape selbst ist im Node-Test grün (fail 0).


Generated by Claude Code

lukisch commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Triage (Cloud-Bot): CI-Diagnose

test (ubuntu-latest, 3.10/3.11) schlägt nicht wegen der Änderung in diesem PR fehl. Der Selbsttest-Subprozess stürzt in highlightBlock (main.py:259) mit none_dealloc ab (returncode -6). Ursache ist die PySide6-6.12.0-Regression.

Der Fix liegt in #11 (Ausschluss von 6.12.0), und #11 ist grün. Empfehlung: #11 zuerst mergen, dann #10 auf main rebasen und die CI erneut laufen lassen. Die Escaping-Änderung in diesem PR selbst ist von dem Fehler unberührt: die Node-Tests zeigen fail 0. Ich habe nichts gepusht und nichts freigegeben.


Generated by Claude Code

lukisch commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Zweitmodell-Review: Der Fix (escapeHtml(codeBlockLang) im Fence-Renderer) schließt die Attribut-Injektion korrekt; die Node-Tests decken Breakout-Payloads gut ab. Hinweis: CI test (ubuntu-latest, 3.10/3.11) ist rot, 3.12 grün, Node-/Flutter-Jobs grün – die Änderung berührt kein Python, daher vermutlich unabhängig (ggf. vorbestehend auf master; bitte Log der Python-Jobs prüfen/erneut laufen lassen). Keine Blocker am Code selbst; Merge-Freigabe bleibt beim Maintainer.


Generated by Claude Code

lukisch commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Diagnose: Die roten Jobs (ubuntu 3.10/3.11) brechen in test_self_test_preserves_existing_user_settings_bytes_and_mtime mit Fatal Python error: none_dealloc in highlightBlock. Das ist der PySide6-6.12.0-Absturz (siehe UniversalDocsGrabber#5), nicht der Fence-Escape-Fix. Vorschlag: PySide6 in requirements*.txt und pyproject.toml mit !=6.12.0 ausschließen, dann CI neu starten.


Generated by Claude Code

@lukisch lukisch left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zweitmodell-Review (Head 10ab7ed): Code-Fix korrekt, CI-Rot ist nicht durch dieses PR verursacht.

  • Die Änderung escapt codeBlockLang mit escapeHtml vor dem Einsetzen ins class-Attribut. Das behebt die beschriebene Attribut-Injektion. Die Tests laden die ausgelieferten Funktionen per vm und werten kein HTML aus. Das ist sauber.
  • Die Fehler in test (ubuntu-latest, 3.10) und (3.11) sind ein harter Abbruch in main.py:259 highlightBlock (Fatal Python error: none_dealloc) in test_file_handling.py. Das ist die PySide6-6.12.0-Regression. main schließt sie bereits mit ed46284 (!=6.12.0), dieser Branch basiert aber auf 0aea162, also davor.
  • Empfehlung: Branch auf aktuelles main rebasen, dann sollten alle acht Zellen grün werden. Ich pushe nicht auf diesen fremden Draft-Branch.
  • Hinweis: actions/setup-node@v4 läuft wegen der Node-20-Deprecation unter erzwungenem Node 24. Das ist nur eine Warnung, passt aber zu den offenen Dependabot-Bumps.

Freigabe/Merge bleibt beim Maintainer.


Generated by Claude Code

lukisch commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Review: Fix korrekt (Sprachattribut der Fence wird per escapeHtml maskiert; XSS-Vektoren "><img onerror> / " onmouseover= im Test abgedeckt). Alle 15 Checks grün (Python 3.10–3.13, Windows/Ubuntu, Flutter, CodeQL). Hinweis: neuer Node-Step im Workflow läuft vor setup-python – unkritisch. Freigabe empfohlen.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant